package com.ydj.framework.redis;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.UUID;

/**
 * 分布式锁对象<br>
 * 用户辅助加锁操作
 *
 * @author wangsc
 * @time 2018年11月5日下午7:34:02
 */

public class DistributedLock {
    private final static Logger logger = LoggerFactory.getLogger(DistributedLock.class);
    /**
     * 默认的锁的超时时长，单位ms,默认60秒
     */
    public static final int DEFAULT_EXPIRY_TIME_MILLIS = Integer.getInteger("com.hori.jedis.lock.expiry.millis", 60 * 1000);
    private static DistributedLock NO_LOCK = new DistributedLock("default", new UUID(0L, 0L), 0L);
    /**
     * 锁的key
     */
    private String lockKey;
    /**
     * uuid，用于更精确辅助判断锁对象信息的比较是否一致
     */
    private UUID uuid;
    /**
     * 锁的超时时间点的时间戳毫秒，注意是时间戳
     */
    private long expiryTime;
    /**
     * 获取锁是否成功的标志，用于控制释放锁的误操作，只有lockSuccess为true时，才能释放锁
     */
    private boolean lockSuccess = false;

    /**
     * 无参构造函数是私有的
     */
    private DistributedLock() {

    }

    /**
     * 构造函数<br>
     * 默认锁的超时时间60s
     *
     * @param lockKey 锁的名称，注意保持其可识别性；lockKey不能包含冒号:分隔
     */
    public DistributedLock(String lockKey) {
        if (StringUtils.isBlank(lockKey)) {
            throw new RuntimeException("DistributedLock lockKey cannot be null");
        }
        if (-1 != lockKey.indexOf(":")) {//lockKey不能使用冒号:分隔
            throw new RuntimeException("DistributedLock lockKey不能包含冒号:分隔");
        }
        this.lockKey = lockKey;
        this.uuid = UUID.randomUUID();
        long expiryTimeMillis = DEFAULT_EXPIRY_TIME_MILLIS;
        this.expiryTime = expiryTimeMillis;//###加上当前系统时间，转成时间戳
        this.lockSuccess = false;
    }

    /**
     * 构造函数,外部调用
     *
     * @param lockKey          锁的名称，注意保持其可识别性；lockKey不能包含冒号:分隔
     * @param expiryTimeMillis 锁的超时时间，单位ms,如锁超时时间60秒，则是60*1000
     */
    public DistributedLock(String lockKey, long expiryTimeMillis) {
        if (StringUtils.isBlank(lockKey)) {
            throw new RuntimeException("DistributedLock lockKey cannot be null");
        }
        this.lockKey = lockKey;
        this.uuid = UUID.randomUUID();
        this.expiryTime = expiryTimeMillis;//###加上当前系统时间，转成时间戳
        this.lockSuccess = false;
    }

    /**
     * 构造函数，私有构造函数
     *
     * @param lockKey          锁的名称，注意保存可识别性，同时用于控制锁的粒度
     * @param expiryTimeMillis 锁的超时时间，单位ms,如锁超时时间60秒，则是60*1000
     */
    private DistributedLock(String lockKey, UUID uuid, long expiryTimeMillis) {
        this.lockKey = lockKey;
        this.uuid = uuid;
        this.expiryTime = expiryTimeMillis;//###加上当前系统时间，转成时间戳
        this.lockSuccess = false;
    }

    /**
     * 根据字符串生成锁对象
     *
     * @param text
     * @return
     */
    public static DistributedLock fromString(String text) {
        /*try {
            String[] parts = text.split(":");
            String theLockKey=parts[0];
            UUID theUUID = UUID.fromString(parts[1]);
            long theTime = Long.parseLong(parts[2]);
            return new DistributedLock(theLockKey,theUUID, theTime);
        } catch (Exception e) {
        	e.printStackTrace();
            return NO_LOCK;
        }*/
        String[] parts = text.split(":");
        String theLockKey = parts[0];
        UUID theUUID = UUID.fromString(parts[1]);
        long theTime = Long.parseLong(parts[2]);
        DistributedLock instance = new DistributedLock();
        instance.lockKey = theLockKey;
        instance.uuid = theUUID;
        instance.expiryTime = theTime;
        return instance;
    }

    public UUID getUUID() {
        return uuid;
    }

    public long getExpiryTime() {
        return expiryTime;
    }

    public String getLockKey() {
        return lockKey;
    }

    public void setLockKey(String lockKey) {
        this.lockKey = lockKey;
    }

    /**
     * 重写toString
     */
    @Override
    public String toString() {
        return lockKey + ":" + uuid.toString() + ":" + expiryTime;
    }

    /**
     * 判断锁是否超时
     *
     * @return
     */
    boolean isExpired() {
        //logger.info("判断锁是否超时，lock:"+this.toString()+",getExpiryTime:"+getExpiryTime()+",now:"+System.currentTimeMillis());
        return getExpiryTime()<0;
    }

    /**
     * @param otherUUID
     * @return
     */
    boolean isExpiredAndMine(UUID otherUUID) {
        //System.out.println("##isExpired:"+this.isExpired());
        //System.out.println("##this.getUUID().equals(otherUUID):"+this.getUUID().equals(otherUUID));
        return this.isExpired() && this.getUUID().equals(otherUUID);
    }

    /**
     * 设置当前锁对象加锁成功<br>
     * protected方法对调用做限制
     */
    protected void setLoginSuccess() {
        this.lockSuccess = true;
    }

    /**
     * 获取锁是否成功
     *
     * @return
     */
    public boolean getLockSuccess() {
        return this.lockSuccess;
    }

    public static void main(String[] args) {
        DistributedLock lock = DistributedLock.fromString("lock_prize_id_1@2:9e88421d-f5cc-4777-bc2d-3f7feb514bee:1512389761366");
        System.out.println(lock.getExpiryTime());
    }
}
